<script setup lang="ts">
import RoomStatus from './components/RoomStatus.vue'
import RoomAction from './components/RoomAction.vue'
import RoomMessage from './components/RoomMessage.vue'

import { baseURL } from '@/utils/request'
import { useUserStore } from '@/stores'
import { useRoute } from 'vue-router'
import { io, type Socket } from 'socket.io-client'
import { onMounted, onUnmounted, ref, nextTick } from 'vue'
import type { TimeMessages, Message } from '@/types/room'
import type { ConsultOrderItem, Image } from '@/types/consult'
import { MsgType, OrderType } from '@/enums'
import { getConsultOrderDetail } from '@/services/consult'
import dayjs from 'dayjs'
import { showToast } from 'vant'
import { provide } from 'vue'

const store = useUserStore()
const route = useRoute()

// 创建变量 socket io 存链接实例
let socket: Socket

// 渲染整个页面的列表
const list = ref<Message[]>([])

const consult = ref<ConsultOrderItem>()
// 创建了问诊信息对象后, 通过依赖注入, 传给子孙组件使用
provide('consult', consult)

// 更新订单数据
const getOrderDetail = async () => {
  const res = await getConsultOrderDetail(route.query.orderId as string)
  console.log(res.data)

  consult.value = res.data
}

const isInit = ref(true)

// 页面挂载
onMounted(() => {
  // 页面进入, 获取一次订单数据
  getOrderDetail()
  // 创建连接实例(这时候马上就会连接)
  socket = io(baseURL, {
    auth: {
      token: `Bearer ${store.user?.token}`
    },
    query: {
      orderId: route.query.orderId
    }
  })

  // 监听链接成功事件
  socket.on('connect', () => {
    console.log('成功连接')
  })

  // 错误异常消息
  socket.on('error', () => {
    console.log('socket io 异常')
  })

  // 已经断开连接
  socket.on('disconnect', () => {
    console.log('socket io 断开链接')
  })

  // 监听聊天记录事件
  socket.on('chatMsgList', ({ data }: { data: TimeMessages[] }) => {
    // 创建一个列表, 用来存放最终的消息列表
    const arr: Message[] = []
    console.log('聊天记录数组', data)
    // data 是聊天记录数组
    data.forEach((item, i) => {
      // 处理聊天记录的时候, 吧当前聊天记录的第一条(最旧)时间记录下来, 下次再次请求,就以这个为标准
      if (i === 0) time.value = item.createTime
      // 每遍历到一个聊天记录(以时间为分割的一系列消息组成的对象)
      // 先放当前消息的时间说明 (10:03)
      arr.push({
        msgType: MsgType.Notify,
        msg: { content: item.createTime },
        createTime: item.createTime,
        id: item.createTime
      })
      arr.push(...item.items)
    })
    console.log('消息列表', arr)
    // 将处理完的数据, 放入渲染列表当中
    // TODO: 记住后面这里要用 unshift
    list.value.unshift(...arr)

    // 因为要兼容向上翻更旧列表的功能, 所以要做特殊处理
    loading.value = false
    // 如果没有更多数据, 就提示用户
    if (!data.length) return showToast('没有更多记录')
    // 第一次进入页面时, 应该主动滚动到底部让用户看到最新聊天
    // 记得等待渲染完毕
    const dom = document.querySelector('.msg')
    nextTick(() => {
      if (isInit.value) {
        // 如果第一次进来, 滚动到页面底部
        window.scrollTo(0, document.body.scrollHeight)
        isInit.value = false
        // 同时标记所有消息已读(其实就是标记最后一个, 目前没有什么效果)
        socket.emit('updateMsgStatus', arr[arr.length - 1].id)
      } else {
        // 如果是向上加载更多数据, 其实还是应该之前记录的那个dom显示在页面上才对
        dom?.scrollIntoView()
        // 微调
        window.scrollBy(0, -150)
      }
    })
  })

  // 监听订单状态变化
  socket.on('statusChange', () => {
    // 重新获取状态数据
    getOrderDetail()
  })

  // 接收消息 在onMounted注册
  socket.on('receiveChatMsg', async (event) => {
    list.value.push(event)
    // 等待新数据渲染完毕, 滚动到页面底部
    await nextTick()
    window.scrollTo(0, document.body.scrollHeight)
    // 现在还要记录当前新消息已读(目前没有什么效果)
    socket.emit('updateMsgStatus', event.id)
  })
})

// 页面跳出
onUnmounted(() => {
  // 关闭 socket io 连接
  socket.close()
})

// 发送文字
const sendText = (text: string) => {
  // 每当子组件触发了要发送文字的时间
  // 往聊天室服务器触发
  socket.emit('sendChatMsg', {
    from: store.user?.id,
    to: consult.value?.docInfo?.id,
    msgType: MsgType.MsgText,
    msg: { content: text }
  })
}
// 发送图片
const sendImage = (img: Image) => {
  socket.emit('sendChatMsg', {
    from: store.user?.id,
    to: consult.value?.docInfo?.id,
    msgType: MsgType.MsgImage,
    msg: { picture: img }
  })
}

// 下拉加载更多
// 是否加载中
const loading = ref(false)
// 加载更多函数
const onRefresh = () => {
  // 加载更多时, 带上的参数包括每页条数, 上次加载的旧时间, 当前 orderId
  socket.emit('getChatMsgList', 20, time.value, route.query.orderId)
}
// 记录现在加载的聊天记录时间, 默认就是当下
const time = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))

// 修改评价数据的函数
const completeEva = (score: number) => {
  const item = list.value.find((item) => item.msgType === MsgType.CardEvaForm)
  if (item) {
    item.msg.evaluateDoc = { score }
    item.msgType = MsgType.CardEva
  }
}
// 提供给所有后代组件
provide('completeEva', completeEva)
</script>

<template>
  <div class="room-page">
    <cp-nav-bar title="问诊室" />
    <!-- 顶部状态栏 -->
    <room-status
      :status="consult?.status"
      :countdown="consult?.countdown"
    ></room-status>
    <!-- 中间的卡片列表 -->
    <van-pull-refresh v-model="loading" @refresh="onRefresh">
      <room-message :list="list"></room-message>
    </van-pull-refresh>
    <!-- 底部操作栏 -->
    <room-action
      :disabled="consult?.status !== OrderType.ConsultChat"
      @send-text="sendText"
      @send-image="sendImage"
    ></room-action>
  </div>
</template>

<style lang="scss" scoped>
.room-page {
  padding-top: 50px;
  padding-bottom: 60px;
  min-height: 100vh;
  box-sizing: border-box;
  background-color: var(--cp-bg);
  .van-pull-refresh {
    width: 100%;
    min-height: calc(100vh - 150px);
  }
}
</style>
